package com.cloudkinto.common.utils.ali;

import com.aliyun.oss.*;
import com.aliyun.oss.model.*;
import com.cloudkinto.common.common.DateUtils;
import com.cloudkinto.common.constant.GlobalConstants;
import com.cloudkinto.common.utils.TimeUtils;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Decoder;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author fanp
 * @version v1.0.0
 * @Description :
 * @Create on : 2021/2/2 16:40
 **/
public class AliOss {
//    private static String endpoint = "oss-cn-hangzhou.aliyuncs.com";//外网
        private static String endpoint = "oss-cn-hangzhou-internal.aliyuncs.com";//内网
    private static String accessKeyId = "LTAI4GACEnVYG5jtk7AsZsH6";
    private static String accessKeySecret = "FdFWRYy5W3jkV7hhricpzinLl4XR8n";
    private static String bucketName = "cloudkinto-1";
    public final static String objectName = "cloudkint-file/";
    public final static String template = "cloudkint-file/template/";
    public final static String temporaryFile = "temporaryFile/";
    private static String objectNameTemporary = "";

    //上传文件到阿里Oss (从临时文件夹中复制到现文件夹中 并删除临时文件夹中的文件)
    public static void uploadFile(String path, String suffix, Long fileId) {
        uploadFile(path, new Date(), suffix, fileId);
    }

    //上传文件到阿里Oss (从临时文件夹中复制到现文件夹中 并删除临时文件夹中的文件)
    public static void uploadFile(String path, Date fileCreateDate,String suffix, Long fileId) {
        if (GlobalConstants.IMG_SUFFIX.contains(suffix)) {
            objectNameTemporary = objectName + DateUtils.getTodayYYMMStr(fileCreateDate) + "/" + "photo" + "/" + fileId + "." + suffix;
        } else {
            objectNameTemporary = objectName + DateUtils.getTodayYYMMStr(fileCreateDate) + "/" + "document" + "/" + fileId + "." + suffix;
        }
        //创建OSSclient
        OSS oss = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        //复制  在同一个域下的不同文件夹就行复制  eg:"cloudkint-file/temporaryFile/3118.png"
        CopyObjectRequest copyObjectRequest = new CopyObjectRequest(bucketName, path, bucketName, objectNameTemporary);
        //判断这个文件是否存在
        if (!oss.doesObjectExist(bucketName, path)) {
            return;
        }
        oss.copyObject(copyObjectRequest);
        //将临时文件删除  注意：阿里OSS删除  默认如果子文件夹下面无内容会将子文件夹一起删除
        oss.deleteObject(bucketName, path);
        // 关闭OSSClient
        oss.shutdown();
    }


    //文件图片直接上传到阿里云Oss
    public static void uploadFile(InputStream inputStream, String suffix, Long fileId) {
        OSS oss = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        if (GlobalConstants.IMG_SUFFIX.contains(suffix)) {
            objectNameTemporary = objectName + DateUtils.getTodayYYMMStr() + "/" + "photo" + "/" + fileId + "." + suffix;
        } else {
            objectNameTemporary = objectName + DateUtils.getTodayYYMMStr() + "/" + "document" + "/" + fileId + "." + suffix;
        }
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectNameTemporary, inputStream);
        try {
            oss.putObject(putObjectRequest);
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (oss != null) {
                oss.shutdown();
            }
        }
    }

    //设置一个存储临时 都可存
    public static void temporaryFile(Long fileId, String suffix, MultipartFile file) throws Exception {
        //创建一个oss实例
        OSS oss = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        objectNameTemporary = objectName + "temporaryFile/" + fileId + "." + suffix;
        //上传
        InputStream inputStream = file.getInputStream();
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectNameTemporary, inputStream);
        oss.putObject(putObjectRequest);
        oss.shutdown();
    }

    //设置一个存储临时 都可存
    public static void temporaryFile(Long fileId, String suffix, String imgStr) throws Exception {
        //创建一个oss实例
        OSS oss = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        objectNameTemporary = objectName + "temporaryFile/" + fileId + "." + suffix;
        //上传
        BASE64Decoder decoder = new BASE64Decoder();
        //Base64解码
        byte[] b = decoder.decodeBuffer(imgStr);
        for (int i = 0; i < b.length; ++i) {
            if (b[i] < 0) {
                //调整异常数据
                b[i] += 256;
            }
        }
        InputStream inputStream = new ByteArrayInputStream(b);
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectNameTemporary, inputStream);
        oss.putObject(putObjectRequest);
        oss.shutdown();
    }

    public static void temporaryFile2(Long fileId, String suffix, File file) throws Exception {
        //创建一个oss实例
        OSS oss = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        objectNameTemporary = objectName + "temporaryFile/" + fileId + "." + suffix;
        //上传
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectNameTemporary, file);
        oss.putObject(putObjectRequest);
        oss.shutdown();
    }

    /**
     * @param fileName
     * @param file
     * @return 文件名
     * @throws Exception
     */
    public static String temporaryFile2(String fileName, File file) throws Exception {
        //创建一个oss实例
        OSS oss = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        objectNameTemporary = objectName + "temporaryFile/" + fileName;
        //上传
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectNameTemporary, file);
        oss.putObject(putObjectRequest);
        oss.shutdown();
        if (file.exists()) {
            file.delete();
        }
        return "temporaryFile/" + fileName;
    }

    public static void temporaryFile3(Long fileId, String suffix, InputStream inputStream) {
        ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
        // 设置OSSClient允许打开的最大HTTP连接数，默认为1024个。
        conf.setMaxConnections(1024);
        // 设置Socket层传输数据的超时时间，默认为50000毫秒。
        conf.setSocketTimeout(10000);
        // 设置建立连接的超时时间，默认为50000毫秒。
        conf.setConnectionTimeout(10000);
        // 设置从连接池中获取连接的超时时间（单位：毫秒），默认不超时。
        conf.setConnectionRequestTimeout(1000);
        // 设置连接空闲超时时间。超时则关闭连接，默认为60000毫秒。
        //        conf.setIdleConnectionTime(10000);
        // 设置失败请求重试次数，默认为3次。
        conf.setMaxErrorRetry(3);
        //创建一个oss实例
        OSS oss = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret, conf);
        objectNameTemporary = objectName + "temporaryFile/" + fileId + "." + suffix;
        //上传
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectNameTemporary, inputStream);
        try {
            oss.putObject(putObjectRequest);
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (oss != null) {
                oss.shutdown();
            }
        }
    }


    //删除文件
    public static void deleteFile(String path, String suffix, Long fileId) {
        if (GlobalConstants.IMG_SUFFIX.contains(suffix)) {
            objectNameTemporary = objectName + DateUtils.getTodayYYMMStr() + "/" + "photo" + "/" + fileId + "(已删除)." + suffix;
        } else {
            objectNameTemporary = objectName + DateUtils.getTodayYYMMStr() + "/" + "document" + "/" + fileId + "(已删除)." + suffix;
        }
        OSS oss = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        CopyObjectRequest copyObjectRequest = new CopyObjectRequest(bucketName, path, bucketName, objectNameTemporary);
        //判断这个文件是否存在
        if (!oss.doesObjectExist(bucketName, path)) {
            return;
        }
        //暂未有修改文件名的方法 需要copy 然后再修改
        oss.copyObject(copyObjectRequest);
        oss.deleteObject(bucketName, path);
        oss.shutdown();
    }


    /**
     * 列举临时文件夹下得所有文件
     */
    public static List<OSSObjectSummary> getFileList() {
        List<OSSObjectSummary> result = new ArrayList<>();

        int maxKeys = 1000;
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            String nextMarker = null;
            ObjectListing objectListing;

            do {
                objectListing = ossClient.listObjects(new ListObjectsRequest(bucketName).withMarker(nextMarker).withPrefix("cloudkint-file/temporaryFile/").withMaxKeys(maxKeys));
                List<OSSObjectSummary> sums = objectListing.getObjectSummaries();
//                for (OSSObjectSummary s : sums) {
//                    System.out.println("\t" + s.getKey() + ",日期："+DateUtils.dateFormatToString(s.getLastModified(), "yyyy-MM-dd HH:mm:ss"));
//                }
                result.addAll(sums);

                nextMarker = objectListing.getNextMarker();

            } while (objectListing.isTruncated());
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return result;
    }


    /**
     * 删除指定目录下的文件
     * 警告 如果以下示例代码中前缀prefix的值为空字符串或者NULL，将会删除整个Bucket内的所有文件，请谨慎使用。
     */
    public static void autoDeleteFile() {
        int maxKeys = 200;
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            List<String> deleteKeys = new ArrayList<>();//需要删除的文件
            String nextMarker = null;
            ObjectListing objectListing;

            Date date = DateUtils.passingDate(new Date(), -150);
            do {
                //警告 如果以下示例代码中前缀prefix的值为空字符串或者NULL，将会删除整个Bucket内的所有文件，请谨慎使用。
                objectListing = ossClient.listObjects(new ListObjectsRequest(bucketName).withMarker(nextMarker).withPrefix("cloudkint-file/temporaryFile/").withMaxKeys(maxKeys));

                List<OSSObjectSummary> sums = objectListing.getObjectSummaries();
                for (OSSObjectSummary s : sums) {
                    System.out.println("\t" + s.getKey() + ",日期：" + DateUtils.dateFormatToString(s.getLastModified(), "yyyy-MM-dd HH:mm:ss"));
                    if (s.getLastModified().getTime() < date.getTime()) {
                        deleteKeys.add(s.getKey());
                    }
                }

                nextMarker = objectListing.getNextMarker();

            } while (objectListing.isTruncated());

            System.out.println(deleteKeys);
            if (deleteKeys.size() > 0) {
                DeleteObjectsRequest deleteObjectsRequest = new DeleteObjectsRequest(bucketName).withKeys(deleteKeys).withEncodingType("url");
                DeleteObjectsResult deleteObjectsResult = ossClient.deleteObjects(deleteObjectsRequest);
                List<String> deletedObjects = deleteObjectsResult.getDeletedObjects();
                try {
                    for (String obj : deletedObjects) {
                        String deleteObj = URLDecoder.decode(obj, "UTF-8");
                        System.out.println(deleteObj);
                    }
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
            }
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }

    }
}
